/**
 * 模拟event的源码实现
 */

/**
 * 构造函数
 */
function EventEmitter() {
    //记录订阅的事件
    this._events = {};
}

/**
 * 订阅事件
 * 如果事件是普通事件，要执行newListener的订阅，固定写法
 * @param {事件名称} event 
 * @param {回调} callback 
 */
EventEmitter.prototype.on = function (event, callback) {
    //为了兼容继承EventEmitter，那么属性this._events就得加个判断
    if (!this._events) {
        // 为什么不直接写{},因为直接写的{}有__proto__指向Object
        this._events = Object.create(null);
    }
    //这个要放在绑定之前去执行。
    if (event != 'newListener' && this._events['newListener']) {
        this._events['newListener'].forEach(fn => fn());
        //现在的效果是同步的，如果监听newListener的回调中触发了发布事件，这个时候，发布是不会触发本次订阅的，因为还没有加进去，怎么办呢？
        //如果想解决的话，就在发布的时候，用process.nextTick()来发布
    }
    //如果存在就push、不存在就新增
    if (this._events[event]) {
        this._events[event].push(callback);
    } else {
        this._events[event] = [callback];
    }
}

/**
 * 发布事件
 * @param {事件名称} event 
 */
EventEmitter.prototype.emit = function (event, ...args) {
    if (this._events[event]) {
        this._events[event].forEach(fn => fn.call(this, ...args));
    }
}

/**
 * 移除订阅的事件
 * @param {事件名称} event 
 * @param {回调函数名} callback 
 */
EventEmitter.prototype.off = function (event, callback) {
    if (this._events[event]) {
        this._events[event] = this._events[event].filter(fn => fn != callback);
    }
}

/**
 * 一次性的订阅
 * 一次性的订阅怎么办呢？执行完了删除就可以了
 * @param {事件名称} event 
 * @param {回调函数名} callback 
 */
EventEmitter.prototype.once = function (event, callback) {
    /**
     * 那么怎么删除呢？最直接的想到的就是说在发布的时候，移除，但是不好做，你还得搞个标记。
     * 那如果我们用一个函数来包裹一下传入的回调呢？在执行完毕之后，删掉
     */
    let temp = (...params) => {
        callback.call(this, ...params);
        //移除
        this.off(temp);
    }
    this.on(event, temp);
}


//导出构造函数
module.exports = EventEmitter;